home *** CD-ROM | disk | FTP | other *** search
- #if !defined(lint) && !defined(DOS)
- static char rcsid[] = "$Id: mailcap.c,v 1.38 1996/03/15 07:13:42 hubert Exp $";
- #endif
- /*----------------------------------------------------------------------
-
- T H E P I N E M A I L S Y S T E M
-
- Laurence Lundblade, Mike Seibel and David Miller
- Networks and Distributed Computing
- Computing and Communications
- University of Washington
- 4545 Builiding, JE-20
- Seattle, Washington, 98195, USA
- Internet: mikes@cac.washington.edu
- dlm@cac.wasington.edu
-
- Please address all bugs and comments to "pine-bugs@cac.washington.edu"
-
-
- Pine and Pico are registered trademarks of the University of Washington.
- No commercial use of these trademarks may be made without prior written
- permission of the University of Washington.
-
- Pine, Pico, and Pilot software and its included text are Copyright
- 1989-1996 by the University of Washington.
-
- The full text of our legal notices is contained in the file called
- CPYRIGHT, included with this distribution.
-
-
- Pine is in part based on The Elm Mail System:
- ***********************************************************************
- * The Elm Mail System - Revision: 2.13 *
- * *
- * Copyright (c) 1986, 1987 Dave Taylor *
- * Copyright (c) 1988, 1989 USENET Community Trust *
- ***********************************************************************
-
-
- *******************************************************
- Mailcap support is based in part on Metamail version 2.7:
- Author: Nathaniel S. Borenstein, Bellcore
-
- Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore)
-
- Permission to use, copy, modify, and distribute this material
- for any purpose and without fee is hereby granted, provided
- that the above copyright notice and this permission notice
- appear in all copies, and that the name of Bellcore not be
- used in advertising or publicity pertaining to this
- material without the specific, prior written permission
- of an authorized representative of Bellcore. BELLCORE
- MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY
- OF THIS MATERIAL FOR ANY PURPOSE. IT IS PROVIDED "AS IS",
- WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
- *******************************************************
-
- *******************************************************
- MIME-TYPE support based on code contributed
- by Hans Drexler <drexler@mpi.nl>. His comment:
-
- Mime types makes mime assign attachment types according
- to file name extensions found in a system wide file
- ``/usr/local/lib/mime.types'' and a user specific file
- ``~/.mime.types'' . These files specify file extensions
- that will be connected to a mime type.
- *******************************************************
-
-
- ----------------------------------------------------------------------*/
-
- /*======================================================================
- mailcap.c
-
- Functions to support "mailcap" (RFC1524) to help us read MIME
- segments of various types, and ".mime.types" ala NCSA Mosaic to
- help us attach various types to outbound MIME segments.
-
- ====*/
-
- #include "headers.h"
-
- /*
- * We've decided not to implement the RFC1524 standard minimum path, because
- * some of us think it is harder to debug a problem when you may be misled
- * into looking at the wrong mailcap entry. Likewise for MIME.Types files.
- */
- #if defined(DOS) || defined(OS2)
- #define MC_PATH_SEPARATOR ';'
- #define MT_PATH_SEPARATOR ';'
- #define MT_USER_FILE "mimetype"
- #else /* !DOS */
- #define MC_PATH_SEPARATOR ':'
- #define MC_STDPATH \
- ".mailcap:/etc/mailcap:/usr/etc/mailcap:/usr/local/etc/mailcap"
- #define MT_PATH_SEPARATOR ':'
- #define MT_STDPATH \
- ".mime.types:/etc/mime.types:/usr/local/lib/mime.types"
- #endif /* !DOS */
-
- #define LINE_BUF_SIZE 2000
-
- typedef struct mcap_entry {
- struct mcap_entry *next;
- int needsterminal; /* currently unused */
- char *contenttype;
- char *command;
- char *testcommand;
- char *label; /* unused */
- char *printcommand; /* unused */
- } MailcapEntry;
-
- MailcapEntry *mc_head = NULL,
- *mc_tail = NULL;
- static int mc_is_initialized = 0;
-
-
- /*
- * Internal prototypes
- */
- void mc_addtolist PROTO((MailcapEntry *));
- char *mc_bld_test_cmd PROTO((char *, int, char *, PARAMETER *));
- char *mc_cmd_bldr PROTO((char *, int, char *, PARAMETER *, char *));
- int mc_ctype_match PROTO((int, char *, char *));
- MailcapEntry *mc_get_command PROTO((int, char *, PARAMETER *));
- int mc_get_entry PROTO((FILE *, MailcapEntry *));
- char *mc_get_next_piece PROTO((char *, char **));
- void mc_init PROTO((void));
- int mc_passes_test PROTO((MailcapEntry *, int, char *, PARAMETER *));
- void mc_process_file PROTO((char *));
- void mt_get_file_ext PROTO((char *, char **));
- int mt_use_mime_type PROTO((BODY *, char *));
- int mt_browse_types_file PROTO((BODY *, char *, char *));
- int mt_translate_type PROTO((char *));
- int mt_traverse_types_file PROTO((BODY *, char *, FILE *));
-
-
-
- /*
- * mc_init - Run down the path gathering all the mailcap entries.
- * Returns with the Mailcap list built.
- */
- void
- mc_init()
- {
- char *s,
- *pathcopy,
- *path;
-
- if(mc_is_initialized)
- return;
-
- dprint(2, (debugfile, "- mc_init -\n"));
-
- if(ps_global->VAR_MAILCAP_PATH)
- /* there may need to be an override specific to pine */
- pathcopy = cpystr(ps_global->VAR_MAILCAP_PATH);
- else if((path = getenv("MAILCAPS")) != (char *)NULL)
- /* rfc1524 specifies MAILCAPS as a path override */
- pathcopy = cpystr(path);
- else{
- #if defined(DOS) || defined(OS2)
- /*
- * This gets interesting. Since we don't have any standard location
- * for config/data files, look in the same directory as the PINERC
- * and the same dir as PINE.EXE. This is similar to the UNIX
- * situation with personal config info coming before
- * potentially shared config data...
- */
- s = last_cmpnt(ps_global->pinerc);
- if(s != NULL){
- strncpy(tmp_20k_buf, ps_global->pinerc, s - ps_global->pinerc);
- tmp_20k_buf[s - ps_global->pinerc] = '\0';
- }
- else
- strcpy(tmp_20k_buf, ".\\");
-
- sprintf(tmp_20k_buf + strlen(tmp_20k_buf),
- "MAILCAP%c%s\\MAILCAP",
- MC_PATH_SEPARATOR,
- ps_global->pine_dir);
- #else /* !DOS */
- build_path(tmp_20k_buf, ps_global->home_dir, MC_STDPATH);
- #endif /* !DOS */
- pathcopy = cpystr(tmp_20k_buf);
- }
-
- path = pathcopy; /* overloaded "path" */
-
- /*
- * Insert an entry for the image-viewer variable from .pinerc, if present.
- */
- if(ps_global->VAR_IMAGE_VIEWER && *ps_global->VAR_IMAGE_VIEWER){
- MailcapEntry mc;
- char *p;
-
- p = tmp_20k_buf;
- sstrcpy(&p, ps_global->VAR_IMAGE_VIEWER);
- sstrcpy(&p, " %s");
- mc.command = cpystr(tmp_20k_buf);
- mc.contenttype = cpystr("image/*");
- mc.testcommand = (char *)NULL;
- mc.printcommand = (char *)NULL;
- mc.needsterminal = 0;
- mc.label = cpystr("Pine Image Viewer");
- mc.next = (MailcapEntry *)NULL;
-
- mc_addtolist(&mc);
- dprint(5, (debugfile, "mailcap: using image-viewer=%s\n",
- ps_global->VAR_IMAGE_VIEWER));
- }
-
- dprint(7, (debugfile, "mailcap: path: %s\n", path));
- while(path){
- s = strindex(path, MC_PATH_SEPARATOR);
- if(s)
- *s++ = '\0';
- mc_process_file(path);
- path = s;
- }
-
- if(pathcopy)
- fs_give((void **)&pathcopy);
-
- mc_is_initialized++;
-
- #ifdef DEBUG
- if(debug >= 11){
- MailcapEntry *mc;
- int i = 0;
-
- dprint(11, (debugfile, "Collected mailcap entries\n"));
- for(mc = mc_head; mc; mc = mc->next){
-
- dprint(11, (debugfile, "%d: ", i++));
- if(mc->label)
- dprint(11, (debugfile, "%s\n", mc->label));
- if(mc->contenttype)
- dprint(11, (debugfile, " %s", mc->contenttype));
- if(mc->command)
- dprint(11, (debugfile, " command: %s\n", mc->command));
- if(mc->testcommand)
- dprint(11, (debugfile, " testcommand: %s", mc->testcommand));
- if(mc->printcommand)
- dprint(11, (debugfile, " printcommand: %s", mc->printcommand));
- dprint(11, (debugfile, " needsterminal %d\n", mc->needsterminal));
- }
- }
- #endif /* DEBUG */
- }
-
-
- /*
- * Add all the entries from this file onto the Mailcap list.
- */
- void
- mc_process_file(file)
- char *file;
- {
- MailcapEntry mc;
- int file_check;
- FILE *fp;
- char filebuf[MAXPATH+1];
-
- dprint(2, (debugfile, "mailcap: process_file: %s\n", file));
-
- (void)strncpy(filebuf, file, MAXPATH);
- filebuf[MAXPATH] = '\0';
- file = fnexpand(filebuf, MAXPATH);
- dprint(7, (debugfile, "mailcap: processing file: %s\n", file));
- file_check = is_writable_dir(file);
- switch(file_check){
- case 0: case 1: /* is a directory */
- dprint(2, (debugfile, "mailcap: %s is a directory, should be a file\n",
- file));
- return;
-
- case 2: /* ok */
- break;
-
- case 3: /* doesn't exist */
- dprint(5, (debugfile, "mailcap: %s doesn't exist\n", file));
- return;
-
- default:
- panic("Programmer botch in mc_process_file");
- /*NOTREACHED*/
- }
-
- fp = fopen(file, "r");
-
- if(fp){
- while(mc_get_entry(fp, &mc))
- mc_addtolist(&mc);
-
- (void)fclose(fp);
- }
- }
-
-
- /*
- * Find the next entry in the file pointed to by fp and fill in mc.
- *
- * Returns 1 if it found another entry, 0 if no more entries in file.
- */
- int
- mc_get_entry(fp, mc)
- FILE *fp;
- MailcapEntry *mc;
- {
- char *s, *t, *cont, *raw_entry;
- char linebuf[LINE_BUF_SIZE];
- int raw_entry_alloc, len;
-
- mc->contenttype = (char *)NULL;
- mc->command = (char *)NULL;
- mc->testcommand = (char *)NULL;
- mc->label = (char *)NULL;
- mc->printcommand = (char *)NULL;
- mc->needsterminal = 0;
- mc->next = (MailcapEntry *)NULL;
-
- #define ALLOC_INCREMENT 1000
- raw_entry_alloc = ALLOC_INCREMENT;
- raw_entry = (char *)fs_get((size_t)raw_entry_alloc + 1);
- try_again:
- *raw_entry = '\0';
-
- /* handle continuation lines and comments */
- while(fgets(linebuf, LINE_BUF_SIZE, fp)){
- if(*linebuf == '#' || *linebuf == '\n') /* skip comments and blanks */
- continue;
- len = strlen(linebuf);
- if(linebuf[len-1] == '\n')
- linebuf[--len] = '\0';
- if(len + strlen(raw_entry) > raw_entry_alloc){
- raw_entry_alloc += ALLOC_INCREMENT;
- fs_resize((void **)&raw_entry, (size_t)raw_entry_alloc+1);
- }
- if(linebuf[len-1] == '\\'){
- linebuf[len-1] = '\0';
- (void)strcat(raw_entry, linebuf);
- }
- else{
- (void)strcat(raw_entry, linebuf);
- break;
- }
- }
-
- /* skip leading space in line */
- for(cont = raw_entry; *cont && isspace(*cont); ++cont)
- ;/* do nothing */
- if(!*cont){ /* blank entry */
- if(feof(fp)){ /* end of file */
- if(raw_entry)
- fs_give((void **)&raw_entry);
- dprint(7, (debugfile, "mailcap: end of file\n"));
- return 0;
- }
- goto try_again;
- }
-
- s = strindex(cont, ';');
- if(!s){
- dprint(2, (debugfile, "mailcap: ignoring entry, no semicolon: %s\n",
- raw_entry));
- goto try_again;
- }
-
- dprint(8, (debugfile, "mailcap: processing entry: %s\n", raw_entry));
-
- *s++ = '\0';
-
- /* trim white space, convert to lowercase */
- mc->contenttype = cpystr(strclean(cont));
- dprint(9, (debugfile, "mailcap: content_type: %s\n", mc->contenttype));
-
- /* make implicit wildcard explicit */
- if (strindex(mc->contenttype, '/') == NULL){
- fs_resize((void **)&mc->contenttype, strlen(mc->contenttype) + 3);
- (void)strcat(mc->contenttype, "/*");
- }
-
- t = mc_get_next_piece(s, &mc->command);
- removing_leading_white_space(mc->command);
- dprint(9, (debugfile, "mailcap: command: %s\n", mc->command));
-
- if(!t){
- fs_give((void **)&raw_entry);
- return 1;
- }
-
- /* process fields */
- dprint(9, (debugfile, "mailcap: flags: %s\n", t));
- for(s = t; s; s = t){
- char *arg, *eq;
-
- t = mc_get_next_piece(s, &arg);
- if(*arg)
- removing_leading_white_space(arg);
- eq = strindex(arg, '=');
- if(eq)
- *eq++ = '\0';
-
- if(*arg)
- removing_trailing_white_space(arg);
- if(*arg){
- if(!strcmp(arg, "needsterminal")){
- mc->needsterminal = 1;
- dprint(9, (debugfile, "mailcap: set flag needsterminal\n"));
- }
- else if(!strcmp(arg, "copiousoutput")){
- ;/* not used */
- dprint(9, (debugfile,
- "mailcap: not using flag copiousoutput\n"));
- }
- else if(eq && !strcmp(arg, "test")){
- mc->testcommand = cpystr(eq);
- dprint(9, (debugfile, "mailcap: testcommand=%s\n",
- mc->testcommand));
- }
- else if(eq && !strcmp(arg, "description")){
- mc->label = cpystr(eq);
- dprint(9, (debugfile, "mailcap: label=%s\n",
- mc->label));
- }
- else if(eq && !strcmp(arg, "print")){
- mc->printcommand = cpystr(eq);
- dprint(9, (debugfile, "mailcap: printcommand=%s\n",
- mc->printcommand));
- }
- else if(eq && !strcmp(arg, "compose")){
- ;/* not used */
- dprint(9, (debugfile, "mailcap: not using compose=%s\n", eq));
- }
- else if(eq && !strcmp(arg, "composetyped")){
- ;/* not used */
- dprint(9, (debugfile, "mailcap: not using composetyped=%s\n",
- eq));
- }
- else if(eq && !strcmp(arg, "textualnewlines")){
- ;/* not used */
- dprint(9, (debugfile,
- "mailcap: not using texttualnewlines=%s\n", eq));
- }
- else if(eq && !strcmp(arg, "edit")){
- ;/* not used */
- dprint(9, (debugfile, "mailcap: not using edit=%s\n", eq));
- }
- else if(eq && !strcmp(arg, "x11-bitmap")){
- ;/* not used */
- dprint(9, (debugfile, "mailcap: not using x11-bitmap=%s\n",
- eq));
- }
- else
- dprint(9, (debugfile, "mailcap: ignoring unknown flag: %s\n",
- arg));
- }
-
- if(arg)
- fs_give((void **)&arg);
- }
-
- fs_give((void **)&raw_entry);
- return 1;
- }
-
-
- /*
- * s is a pointer to the current position in the mailcap entry
- *
- * "result" is a pointer to point at an alloc'd copy of the current piece, up
- * to the next ";", and the return value is a pointer to the piece after
- * the ";" (the next "s").
- */
- char *
- mc_get_next_piece(s, result)
- char *s, **result;
- {
- char *s2;
- int quoted = 0;
-
- s2 = (char *)fs_get(strlen(s) * 2 + 1); /* absolute max, if all % signs */
-
- *result = s2;
-
- while(s && *s){
- if(quoted){
- if(*s == '%') /* quoted % turns into %% */
- *s2++ = '%';
-
- *s2++ = *s++;
- quoted = 0;
- }
- else{
- if(*s == ';'){
- *s2 = '\0';
- dprint(9, (debugfile, "mailcap: mc_get_next_piece: %s\n",
- *result));
- return(++s);
- }
- #if defined(DOS) || defined(OS2)
- /*
- * RFC 1524 says that backslash is used to quote
- * the next character, but since backslash is part of pathnames
- * on DOS we're afraid people will not put double backslashes
- * in their mailcap files. Therefore, we violate the RFC by
- * looking ahead to the next character. If it looks like it
- * is just part of a pathname, then we consider a single
- * backslash to *not* be a quoting character, but a literal
- * backslash instead.
- */
- else if(*s == '\\'){
- int t;
-
- t = *(s+1);
- /*
- * If next char is any of these, treat the backslash
- * that preceded it like a regular character.
- */
- if(t && isascii(t) &&
- (isalnum(t) || t == '_' || t == '+' || t == '-' ||
- t == '=' || t == '~')){
- *s2++ = *s++;
- }
- /* otherwise, treat it as a quoting backslash */
- else{
- quoted++;
- ++s;
- }
- }
- #else /* !DOS */
- /* backslash quotes the next character */
- else if(*s == '\\'){
- quoted++;
- ++s;
- }
- #endif /* !DOS */
- else
- *s2++ = *s++;
- }
- }
-
- *s2 = '\0';
-
- dprint(9, (debugfile, "mailcap: mc_get_next_piece(last): %s\n", *result));
-
- return NULL;
- }
-
-
- /*
- * Returns the mailcap entry for type/subtype from the successfull
- * mailcap entry, or NULL if none. Command string still contains % stuff.
- */
- MailcapEntry *
- mc_get_command(type, subtype, params)
- int type;
- char *subtype;
- PARAMETER *params;
- {
- MailcapEntry *mc;
-
- dprint(4, (debugfile, "- mc_get_command(%s/%s) -\n",
- body_type_names(type), subtype));
-
- for(mc = mc_head; mc; mc = mc->next){
- if(mc_ctype_match(type, subtype, mc->contenttype) &&
- mc_passes_test(mc, type, subtype, params)){
-
- dprint(9, (debugfile,
- "mc_get_command: type=%s/%s, command=%s\n",
- body_type_names(type), subtype, mc->command));
- return(mc);
- }
- }
- return((MailcapEntry *)NULL);
- }
-
-
- /*
- * Check whether the pattern "pat" matches this type/subtype.
- * Returns 1 if it does, 0 if not.
- */
- int
- mc_ctype_match(type, subtype, pat)
- int type;
- char *subtype;
- char *pat;
- {
- int len, rv;
- char *type_txt;
- char *full_ctype;
- char *p;
-
- type_txt = body_type_names(type);
- len = strlen(subtype) + strlen(type_txt);
- full_ctype = (char *)fs_get((size_t)len + 1 + 1);
- p = full_ctype;
- sstrcpy(&p, type_txt);
- sstrcpy(&p, "/");
- sstrcpy(&p, subtype);
-
- dprint(4, (debugfile,
- "mc_ctype_match: trying entry %s for %s\n", pat, full_ctype));
-
- rv = 0;
-
- /* check for exact match */
- if(!strucmp(full_ctype, pat))
- rv = 1;
-
- /* check for wildcard match */
- else if ((len=strlen(pat)) >= 2
- && (pat[--len] == '*')
- && (pat[--len] == '/')
- && (!struncmp(full_ctype, pat, len))
- && ((full_ctype[len] == '/') || (full_ctype[len] == '\0')))
- rv = 1;
-
- fs_give((void **)&full_ctype);
- return(rv);
- }
-
-
- /*
- * Run the test command for entry mc to see if this entry currently applies to
- * applies to this type/subtype.
- *
- * Returns 1 if it does pass test (exits with status 0), 0 otherwise.
- */
- int
- mc_passes_test(mc, type, subtype, params)
- MailcapEntry *mc;
- int type;
- char *subtype;
- PARAMETER *params;
- {
- char *cmd = NULL;
- int rv;
-
- dprint(2, (debugfile, "- mc_passes_test -\n"));
-
- if(mc->testcommand && *mc->testcommand)
- cmd = mc_bld_test_cmd(mc->testcommand, type, subtype, params);
-
- if(!mc->testcommand || !cmd || !*cmd){
- if(cmd)
- fs_give((void **)&cmd);
- dprint(7, (debugfile, "no test command, so Pass\n"));
- return 1;
- }
-
- rv = exec_mailcap_test_cmd(cmd);
- dprint(7, (debugfile, "mc_passes_test: \"%s\" %s (rv=%d)\n",
- cmd, rv ? "Failed" : "Passed", rv)) ;
-
- fs_give((void **)&cmd);
-
- return(!rv);
- }
-
-
- int
- mailcap_can_display(type, subtype, params)
- int type;
- char *subtype;
- PARAMETER *params;
- {
- dprint(5, (debugfile, "- mailcap_can_display -\n"));
-
- if(!mc_is_initialized)
- mc_init();
-
- return(mc_get_command(type, subtype, params) ? 1 : 0);
- }
-
-
- char *
- mailcap_build_command(body, tmp_file, needsterm)
- BODY *body;
- char *tmp_file;
- int *needsterm;
- {
- MailcapEntry *mc;
- char *command;
-
- dprint(2, (debugfile, "- mailcap_build_command -\n"));
-
- if(!mc_is_initialized)
- mc_init();
-
- mc = mc_get_command((int)body->type, body->subtype, body->parameter);
- if(!mc){
- q_status_message(SM_ORDER, 3, 4, "Error constructing viewer command");
- dprint(2, (debugfile,
- "mailcap_build_command: no command string for %s/%s\n",
- body_type_names((int)body->type), body->subtype));
- return((char *)NULL);
- }
-
- *needsterm = mc->needsterminal;
-
- command = mc_cmd_bldr(mc->command, (int)body->type,
- body->subtype, body->parameter, tmp_file);
-
- dprint(2, (debugfile, "built command: %s\n", command));
-
- return(command);
- }
-
-
- /*
- * mc_bld_test_cmd - build the command to test if the given type flies
- *
- * mc_cmd_bldr's tmp_file argument is NULL as we're not going to
- * decode and write each and every MIME segment's data to a temp file
- * when no test's going to use the data anyway.
- */
- char *
- mc_bld_test_cmd(controlstring, type, subtype, params)
- char *controlstring;
- int type;
- char *subtype;
- PARAMETER *params;
- {
- return(mc_cmd_bldr(controlstring, type, subtype, params, NULL));
- }
-
-
- /*
- * mc_cmd_bldr - construct a command string to execute
- *
- * If tmp_file is null, then the contents of the given MIME segment
- * is not provided. This is useful for building the "test=" string
- * as it doesn't operate on the segment's data.
- *
- * The return value is an alloc'd copy of the command to be executed.
- */
- char *
- mc_cmd_bldr(controlstring, type, subtype, parameter, tmp_file)
- char *controlstring;
- int type;
- char *subtype;
- PARAMETER *parameter;
- char *tmp_file;
- {
- char *from, *to, *s;
- int prefixed = 0, used_tmp_file = 0;
- PARAMETER *parm;
-
- dprint(8, (debugfile, "- mc_cmd_bldr -\n"));
-
- for(from = controlstring, to = tmp_20k_buf; *from; ++from){
- if(prefixed){ /* previous char was % */
- prefixed = 0;
- switch(*from){
- case '%': /* turned \% into this earlier */
- *to++ = '%';
- break;
-
- case 's': /* insert tmp_file name in cmd */
- if(tmp_file){
- used_tmp_file = 1;
- sstrcpy(&to, tmp_file);
- }
- else
- dprint(2, (debugfile,
- "mc_cmd_bldr: %%s in cmd but not supplied!\n"));
-
- break;
-
- case 't': /* insert MIME type/subtype */
- /* quote to prevent funny business */
- *to++ = '\'';
- sstrcpy(&to, body_type_names(type));
- *to++ = '/';
- sstrcpy(&to, subtype);
- *to++ = '\'';
- break;
-
- case '{': /* insert requested MIME param */
- s = strindex(from, '}');
- if(!s){
- q_status_message1(SM_ORDER, 0, 4,
- "Ignoring ill-formed parameter reference in mailcap file: %s", from);
- break;
- }
-
- *s = '\0';
- ++from; /* from is the part inside the brackets now */
-
- for(parm = parameter; parm; parm = parm->next)
- if(!strucmp(from, parm->attribute))
- break;
-
- dprint(9, (debugfile,
- "mc_cmd_bldr: parameter %s = %s\n",
- from, parm ? parm->value : "(not found)"));
-
- /*
- * Quote parameter values for /bin/sh.
- * Put single quotes around the whole thing but every time
- * there is an actual single quote put it outside of the
- * single quotes with a backslash in front of it. So the
- * parameter value fred's car
- * turns into 'fred'\''s car'
- */
- *to++ = '\''; /* opening quote */
- if(parm){
- char *p;
-
- /*
- * Copy value, but quote single quotes for /bin/sh
- * Backslash quote is ignored inside single quotes so
- * have to put those outside of the single quotes.
- */
- for(p = parm->value; *p; p++){
- if(*p == '\''){
- *to++ = '\''; /* closing quote */
- *to++ = '\\';
- *to++ = '\''; /* below will be opening quote */
- }
- *to++ = *p;
- }
- }
-
- *to++ = '\''; /* closing quote for /bin/sh */
-
- *s = '}'; /* restore */
- from = s;
- break;
-
- /*
- * %n and %F are used by metamail to support otherwise
- * unrecognized multipart Content-Types. Pine does
- * not use these since we're only dealing with the individual
- * parts at this point.
- */
- case 'n':
- case 'F':
- default:
- dprint(9, (debugfile,
- "Ignoring %s format code in mailcap file: %%%c\n",
- (*from == 'n' || *from == 'F') ? "unimplemented"
- : "unrecognized",
- *from));
- break;
- }
- }
- else if(*from == '%') /* next char is special */
- prefixed = 1;
- else /* regular character, just copy */
- *to++ = *from;
- }
-
- *to = '\0';
-
- /*
- * file not specified, redirect to stdin
- */
- if(!used_tmp_file && tmp_file)
- sprintf(to, " < %s", tmp_file);
-
- return(cpystr(tmp_20k_buf));
- }
-
-
- /*
- * Adds element mc to the mailcap list.
- */
- void
- mc_addtolist(mc)
- MailcapEntry *mc;
- {
- register MailcapEntry *new_mc;
-
- new_mc = (MailcapEntry *)fs_get(sizeof(MailcapEntry));
-
- /*
- * Copy the structure, but don't copy pointed-to strings, just
- * copy the pointers themselves.
- */
- *new_mc = *mc;
-
- /* add to end of list so search order is correct */
- if(mc_tail)
- mc_tail->next = new_mc;
- else
- mc_head = new_mc;
-
- mc_tail = new_mc;
- }
-
-
- void
- mailcap_free()
- {
- MailcapEntry *mc, *mc_next;
-
- dprint(2, (debugfile, "- mailcap_free -\n"));
-
- if(!mc_is_initialized)
- return;
-
- for(mc = mc_head; mc; mc = mc_next){
- mc_next = mc->next;
- if(mc->contenttype)
- fs_give((void **)&mc->contenttype);
- if(mc->command)
- fs_give((void **)&mc->command);
- if(mc->testcommand)
- fs_give((void **)&mc->testcommand);
- if(mc->label)
- fs_give((void **)&mc->label);
- if(mc->printcommand)
- fs_give((void **)&mc->printcommand);
- fs_give((void **)&mc);
- }
-
- mc_is_initialized = 0;
- mc_head = (MailcapEntry *)NULL;
- mc_tail = (MailcapEntry *)NULL;
- }
-
-
-
- /*
- * END OF MAILCAP ROUTINES, START OF MIME.TYPES ROUTINES
- */
-
-
- /*
- * Exported function that does the work of sniffing the mime.types
- * files and filling in the body pointer if found. Returns 1 (TRUE) if
- * extension found, and body pointer filled in, 0 (FALSE) otherwise.
- */
- int
- set_mime_type_by_extension(body, filename)
- BODY *body;
- char *filename;
- {
- char *extension;
-
- mt_get_file_ext(filename, &extension);
- dprint(5, (debugfile, "mt_set_new : filename=%s, extension=%s\n",
- filename, extension));
- return(*extension ? mt_use_mime_type(body, extension) : 0);
- }
-
-
- /*
- * Separate and return a pointer to the first character in the 'filename'
- * character buffer that comes after the rightmost '.' character in the
- * filename. (What I mean is a pointer to the filename - extension).
- */
- void
- mt_get_file_ext(filename, extension)
- char *filename;
- char **extension;
- {
- char *index = NULL;
-
- do
- if(*filename == '.')
- index = filename;
- while (*filename++ != '\0');
-
- *extension = (index) ? index + 1 : filename - 1;
- }
-
-
- /*
- * Read the mime types from appropriate files and compare the extensions.
- * Set the message type if a match can be found.
- */
- int
- mt_use_mime_type(body, extension)
- BODY *body;
- char *extension;
- {
- char *s, *pathcopy, *path;
- int rv = 0;
-
- dprint(2, (debugfile, "- mt_use_mime_type -\n"));
-
- /* We specify MIMETYPES as a path override */
- if(ps_global->VAR_MIMETYPE_PATH)
- /* there may need to be an override specific to pine */
- pathcopy = cpystr(ps_global->VAR_MIMETYPE_PATH);
- else if((path = getenv("MIMETYPES")) != (char *)NULL)
- pathcopy = cpystr(path);
- else{
- #if defined(DOS) || defined(OS2)
- /*
- * This gets interesting. Since we don't have any standard location
- * for config/data files, look in the same directory as the PINERC
- * and the same dir as PINE.EXE. This is similar to the UNIX
- * situation with personal config info coming before
- * potentially shared config data...
- */
- s = last_cmpnt(ps_global->pinerc);
- if(s != NULL){
- strncpy(tmp_20k_buf, ps_global->pinerc, s - ps_global->pinerc);
- tmp_20k_buf[s - ps_global->pinerc] = '\0';
- }
- else
- strcpy(tmp_20k_buf, ".\\");
-
- sprintf(tmp_20k_buf + strlen(tmp_20k_buf),
- "%s%c%s\\%s",
- MT_USER_FILE, MT_PATH_SEPARATOR,
- ps_global->pine_dir, MT_USER_FILE);
- #else /* !DOS */
- build_path(tmp_20k_buf, ps_global->home_dir, MT_STDPATH);
- #endif /* !DOS */
- pathcopy = cpystr(tmp_20k_buf);
- }
-
- path = pathcopy; /* overloaded "path" */
-
- dprint(7, (debugfile, "mime_types: path: %s\n", path));
- while(path){
- if(s = strindex(path, MT_PATH_SEPARATOR))
- *s++ = '\0';
-
- if(rv = mt_browse_types_file(body, extension, path))
- break;
-
- path = s;
- }
-
- if(pathcopy)
- fs_give((void **)&pathcopy);
-
- return(rv);
- }
-
-
- /*
- * Try to match a file extension against extensions found in the file
- * ``filename'' if that file exists. return 1 if a match
- * was found and 0 in all other cases.
- */
- int
- mt_browse_types_file(body, extension, filename)
- BODY *body;
- char *extension;
- char *filename;
- {
- int rv = 0;
- FILE *file;
-
- if(file = fopen(filename, "r")){
- rv = mt_traverse_types_file(body, extension, file);
- fclose(file);
- }
- else
- dprint(1, (debugfile, "mt_browse: FAILED open(%s) : %s.\n",
- filename, error_description(errno)));
-
- return(rv);
- }
-
-
- /*
- * scan each line of the file. Treat each line as a mime type definition.
- * The first word is a type/subtype specification. All following words
- * are file extensions belonging to that type/subtype. Words are separated
- * bij whitespace characters.
- * If a file extension occurs more than once, then the first definition
- * determines the file type and subtype.
- */
- int
- mt_traverse_types_file(body, extension, file)
- BODY *body;
- char *extension;
- FILE *file;
- {
- char buffer[LINE_BUF_SIZE];
-
- /* construct a loop reading the file line by line. Then check each
- * line for a matching definition.
- */
- while(fgets(buffer,LINE_BUF_SIZE,file) != NULL){
- char *typespec;
- char *try_extension;
-
- if(buffer[0] == '#')
- continue; /* comment */
-
- /* remove last character from the buffer */
- buffer[strlen(buffer)-1] = '\0';
- /* divide the input buffer into words separated by whitespace.
- * The first words is the type and subtype. All following words
- * are file extensions.
- */
- dprint(5, (debugfile, "traverse: buffer=%s.\n", buffer));
- typespec = strtok(buffer," \t"); /* extract type,subtype */
- dprint(5, (debugfile, "typespec=%s.\n", typespec));
- while((try_extension = strtok(NULL, " \t")) != NULL){
- /* compare the extensions, and assign the type if a match
- * is found.
- */
- dprint(5, (debugfile,"traverse: trying ext %s.\n", try_extension));
- if(strcmp(try_extension, extension) == 0){
- /* split the 'type/subtype' specification */
- char *type = strtok(typespec,"/");
- char *subtype = strtok(NULL,"/");
- dprint(5, (debugfile, "traverse: type=%s, subtype=%s.\n",
- type,subtype));
- /* The type is encoded as a small integer. we have to
- * translate the character string naming the type into
- * the corresponding number.
- */
- body->type = mt_translate_type(type);
- body->subtype = cpystr(subtype);
- return 1; /* a match has been found */
- }
- }
- }
-
- dprint(5, (debugfile, "traverse: search failed.\n"));
- return 0;
- }
-
-
- /*
- * Translate a character string representing a content type into a short
- * integer number, according to the coding described in c-client/mail.h
- * List of content types taken from rfc1521, September 1993.
- */
- int
- mt_translate_type(type)
- char *type;
- {
- int i;
-
- for (i=0;(i<=TYPEMAX) && body_types[i] && strucmp(type,body_types[i]);i++)
- ;
-
- if (i > TYPEMAX)
- i = TYPEOTHER;
- else if (!body_types[i]) /* if empty slot, assign it to this type */
- body_types[i] = cpystr (type);
-
- return(i);
- }
-